import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import { Client } from 'ssh2';
import { Logger } from '../utils/logger.js';
import { ProgressBar } from '../utils/progressBar.js';
import BatchTransfer from './batchTransfer.js';

export default class SFTPClient {
  constructor() {
    this.client = null;
    this.sftp = null;
    this._isConnected = false; // 改为私有属性
    this.serverInfo = null;
    this.batchTransfer = null;
  }

  /**
   * 检查连接状态
   * @returns {boolean} 是否已连接
   */
  isConnected() {
    return this._isConnected;
  }

  /**
   * 获取连接状态（属性方式）
   * @returns {boolean} 是否已连接
   */
  get connectionStatus() {
    return this._isConnected;
  }

  /**
   * 获取服务器信息
   * @returns {Object} 服务器信息
   */
  getServerInfo() {
    return this.serverInfo;
  }

  /**
   * 格式化文件大小
   * @param {number} bytes - 字节数
   * @returns {string} 格式化后的文件大小
   * @private
   */
  _formatFileSize(bytes) {
    if (bytes === 0) return '0 Bytes';
    
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  async connect(config) {
    return new Promise((resolve, reject) => {
      try {
        this.currentConfig = config;
        const sshConfig = {
          host: config.host,
          port: config.port || 22,
          username: config.username,
          readyTimeout: 30000,
          algorithms: {
            serverHostKey: ['ssh-rsa', 'ssh-dss', 'ecdsa-sha2-nistp256'],
          },
        };

        // 设置认证方式
        if (config.authType === 'password') {
          sshConfig.password = config.password;
        } else if (config.authType === 'key') {
          try {
            sshConfig.privateKey = fs.readFileSync(config.privateKeyPath);
            if (config.passphrase) {
              sshConfig.passphrase = config.passphrase;
            }
          } catch (error) {
            return reject(new Error(`读取私钥失败: ${error.message}`));
          }
        }

        this.client = new Client();

        this.client.on('ready', () => {
          this.client.sftp((err, sftp) => {
            if (err) {
              this._isConnected = false;
              reject(new Error(`获取 SFTP 连接失败: ${err.message}`));
            } else {
              this.sftp = sftp;
      this._isConnected = true;
      
      this.serverInfo = {
        host: config.host,
        port: config.port,
        username: config.username,
        authType: config.privateKey ? '密钥' : '密码'
      };
      
      // 初始化批量传输实例
      this.batchTransfer = new BatchTransfer(this);
      
      Logger.success('SFTP 连接成功');
      resolve();
            }
          });
        });

        this.client.on('error', (err) => {
          this._isConnected = false;
          reject(new Error(`连接错误: ${err.message}`));
        });

        this.client.on('close', () => {
          this._isConnected = false;
          Logger.info('SFTP 连接已关闭');
        });

        this.client.connect(sshConfig);

        // 设置超时
        setTimeout(() => {
          if (!this._isConnected) {
            this.client?.end();
            reject(new Error('连接超时 (30秒)'));
          }
        }, 31000);
      } catch (error) {
        reject(new Error(`连接失败: ${error.message}`));
      }
    });
  }

  async disconnect() {
    return new Promise((resolve) => {
      if (this.client) {
        this.client.end();
        this._isConnected = false;
      }
      resolve();
    });
  }

  async listFiles(remotePath = '/') {
    if (!this.isConnected) {
      throw new Error('未连接到 SFTP 服务器');
    }

    return new Promise((resolve, reject) => {
      this.sftp.readdir(remotePath, (err, files) => {
        if (err) {
          reject(new Error(`列出目录失败: ${err.message}`));
        } else {
          resolve(files);
        }
      });
    });
  }

  async downloadFile(remotePath, localPath, options = {}) {
    if (!this.isConnected()) {
      throw new Error('未连接到 SFTP 服务器');
    }

    const {
      verifyIntegrity = false,
      integrityAlgorithm = 'md5',
      resume = false
    } = options;

    return new Promise(async (resolve, reject) => {
      try {
        // 首先获取文件大小
        this.sftp.stat(remotePath, async (err, stats) => {
          if (err) {
            reject(new Error(`获取文件信息失败: ${err.message}`));
            return;
          }

          const totalBytes = stats.size;
          let downloadedBytes = 0;
          let completed = false;
          let lastUpdateTime = Date.now();

          // 如果启用断点续传，检查本地文件是否存在
          if (resume && fs.existsSync(localPath)) {
            const localStats = fs.statSync(localPath);
            downloadedBytes = localStats.size;
            
            // 如果本地文件大小等于远程文件大小，假设下载已完成
            if (downloadedBytes >= totalBytes) {
              Logger.info(`文件已存在且大小匹配，跳过下载: ${localPath}`);
              
              // 如果启用了完整性验证，则进行验证
              if (verifyIntegrity) {
                const isValid = await this.verifyFileIntegrity(localPath, remotePath, integrityAlgorithm);
                if (isValid) {
                  Logger.success(`文件完整性验证通过: ${localPath}`);
                  resolve();
                  return;
                } else {
                  Logger.warn(`文件完整性验证失败，将重新下载: ${localPath}`);
                  downloadedBytes = 0; // 重置下载字节，重新下载
                }
              } else {
                resolve();
                return;
              }
            }
          }

          const progressBar = new ProgressBar(totalBytes, `下载 ${path.basename(remotePath)}`);
          
          // 优化：根据文件大小动态调整缓冲区
          // 小文件(< 1MB): 64KB
          // 中等文件(1-10MB): 256KB
          // 大文件(10-100MB): 512KB
          // 超大文件(> 100MB): 1MB
          let highWaterMark = 64 * 1024; // 默认 64KB
          if (totalBytes > 100 * 1024 * 1024) {
            highWaterMark = 1024 * 1024; // 1MB
          } else if (totalBytes > 10 * 1024 * 1024) {
            highWaterMark = 512 * 1024; // 512KB
          } else if (totalBytes > 1024 * 1024) {
            highWaterMark = 256 * 1024; // 256KB
          }

          const readOptions = {
            flags: 'r',
            encoding: null,
            autoClose: true,
            highWaterMark: highWaterMark,
            start: resume ? downloadedBytes : 0 // 从断点位置开始读取
          };
          
          const readStream = this.sftp.createReadStream(remotePath, readOptions);
          
          const writeOptions = {
            flags: resume ? 'a' : 'w', // 断点续传使用追加模式
            encoding: null,
            mode: 0o666,
            autoClose: true,
            highWaterMark: highWaterMark,
            start: resume ? downloadedBytes : 0 // 从断点位置开始写入
          };
          
          const writeStream = fs.createWriteStream(localPath, writeOptions);

          // 添加超时处理机制
          let timeoutHandle = null;
          const resetTimeout = () => {
            if (timeoutHandle) clearTimeout(timeoutHandle);
            timeoutHandle = setTimeout(() => {
              if (!completed) {
                cleanup();
                reject(new Error('下载超时 - 30秒内没有数据传输'));
              }
            }, 30000);
          };

          const cleanup = () => {
            if (timeoutHandle) {
              clearTimeout(timeoutHandle);
              timeoutHandle = null;
            }
            if (!readStream.destroyed) readStream.destroy();
            if (!writeStream.destroyed) writeStream.destroy();
          };

          const completeDownload = async () => {
            if (completed) return;
            completed = true;
            cleanup();
            
            // 确保最后一次进度更新
            if (downloadedBytes < totalBytes) {
              progressBar.update(totalBytes);
            }
            progressBar.complete();
            
            // 如果启用了完整性验证，则进行验证
            if (verifyIntegrity) {
              Logger.info(`正在验证文件完整性...`);
              const isValid = await this.verifyFileIntegrity(localPath, remotePath, integrityAlgorithm);
              if (isValid) {
                Logger.success(`文件完整性验证通过: ${localPath}`);
                Logger.success(`文件已下载: ${localPath}`);
                resolve();
              } else {
                Logger.error(`文件完整性验证失败: ${localPath}`);
                fs.unlink(localPath, () => {});
                reject(new Error(`下载的文件完整性验证失败`));
              }
            } else {
              Logger.success(`文件已下载: ${localPath}`);
              resolve();
            }
          };

          const handleError = (err, source) => {
            if (completed) return;
            completed = true;
            cleanup();
            if (!resume) fs.unlink(localPath, () => {});
            reject(new Error(`${source}失败: ${err.message}`));
          };

          // 监听读流事件
          readStream.on('data', (chunk) => {
            resetTimeout();
            downloadedBytes += chunk.length;
            
            // 优化：减少进度条更新频率，避免过多 I/O
            // 大文件每 100ms 更新一次，小文件每次都更新
            const now = Date.now();
            if (totalBytes < 1024 * 1024 || now - lastUpdateTime > 100) {
              progressBar.update(downloadedBytes);
              lastUpdateTime = now;
            }
          });

          readStream.on('error', (err) => {
            handleError(err, '读取文件');
          });

          // 监听写流事件
          writeStream.on('error', (err) => {
            handleError(err, '写入文件');
          });

          // 关键：只有 close 事件表示文件真正写入完成
          writeStream.on('close', () => {
            if (!completed) {
              completeDownload();
            }
          });

          // 开始下载
          resetTimeout();
          readStream.pipe(writeStream);
        });
      } catch (error) {
        reject(new Error(`下载出错: ${error.message}`));
      }
    });
  }

  /**
   * 上传文件到远程服务器
   * @param {string} localPath - 本地文件路径
   * @param {string} remotePath - 远程文件路径
   * @param {Object} options - 上传选项
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadFile(localPath, remotePath, options = {}) {
    const {
      verifyIntegrity = false,
      integrityAlgorithm = 'md5',
      resume = false,
      onProgress = null
    } = options;

    // 检查连接状态
    if (!this.isConnected()) {
      throw new Error('SFTP连接未建立');
    }

    // 检查本地文件是否存在
    if (!fs.existsSync(localPath)) {
      throw new Error(`本地文件不存在: ${localPath}`);
    }

    // 获取本地文件信息
    const stats = fs.statSync(localPath);
    const fileSize = stats.size;

    Logger.info(`开始上传文件: ${localPath} -> ${remotePath} (${this._formatFileSize(fileSize)})`);

    // 创建进度条
    const progressBar = new ProgressBar(fileSize, '上传');

    // 处理断点续传
    let startByte = 0;
    if (resume) {
      try {
        const remoteStats = await this.getFileInfo(remotePath);
        if (remoteStats.size < fileSize) {
          startByte = remoteStats.size;
          Logger.info(`检测到部分文件，将从位置 ${startByte} 继续上传`);
          progressBar.update(startByte);
        } else {
          Logger.info('远程文件已存在且大小匹配，跳过上传');
          progressBar.complete();
          return {
            success: true,
            localPath,
            remotePath,
            size: fileSize,
            skipped: true
          };
        }
      } catch (error) {
        // 远程文件不存在，从头开始上传
        Logger.debug('远程文件不存在，将从头开始上传');
      }
    }

    // 动态调整缓冲区大小
    let highWaterMark;
    if (fileSize < 1024 * 1024) {
      highWaterMark = 64 * 1024; // 64KB for small files
    } else if (fileSize < 10 * 1024 * 1024) {
      highWaterMark = 256 * 1024; // 256KB for medium files
    } else if (fileSize < 100 * 1024 * 1024) {
      highWaterMark = 512 * 1024; // 512KB for large files
    } else {
      highWaterMark = 1024 * 1024; // 1MB for very large files
    }

    // 创建读取流
    const readStream = fs.createReadStream(localPath, {
      start: startByte,
      highWaterMark
    });

    // 创建写入流
    const writeStream = this.sftp.createWriteStream(remotePath, {
      start: startByte,
      highWaterMark
    });

    // 跟踪传输进度
    let transferredBytes = startByte;
    let lastProgressUpdate = Date.now();

    // 设置超时
    const timeout = setTimeout(() => {
      readStream.destroy();
      writeStream.destroy();
      Logger.error('上传超时');
      throw new Error('上传超时');
    }, 30000); // 30秒超时

    return new Promise((resolve, reject) => {
      // 监听读取流数据事件
      readStream.on('data', (chunk) => {
        transferredBytes += chunk.length;
        
        // 更新进度条
        const now = Date.now();
        if (now - lastProgressUpdate > 100 || transferredBytes === fileSize) {
          progressBar.update(transferredBytes);
          lastProgressUpdate = now;
          
          // 调用进度回调
          if (onProgress) {
            onProgress({
              transferred: transferredBytes,
              total: fileSize,
              percentage: Math.round((transferredBytes / fileSize) * 100)
            });
          }
        }
      });

      // 监听读取流结束事件
      readStream.on('end', () => {
        Logger.debug('读取流结束');
      });

      // 监听写入流完成事件
      writeStream.on('close', async () => {
        clearTimeout(timeout);
        progressBar.complete();
        
        // 验证文件完整性
        let integrityVerified = true;
        if (verifyIntegrity) {
          try {
            Logger.debug('验证文件完整性...');
            const localHash = await this.calculateLocalFileHash(localPath, integrityAlgorithm);
            const remoteHash = await this.calculateRemoteFileHash(remotePath, integrityAlgorithm);
            
            if (localHash !== remoteHash) {
              integrityVerified = false;
              Logger.error('文件完整性验证失败');
              reject(new Error('文件完整性验证失败'));
              return;
            }
            
            Logger.debug('文件完整性验证通过');
          } catch (error) {
            Logger.error(`完整性验证出错: ${error.message}`);
            reject(error);
            return;
          }
        }

        Logger.success(`文件上传完成: ${localPath} -> ${remotePath}`);
        resolve({
          success: true,
          localPath,
          remotePath,
          size: fileSize,
          integrityVerified
        });
      });

      // 统一错误处理
      const handleError = (error) => {
        clearTimeout(timeout);
        progressBar.complete();
        Logger.error(`上传失败: ${error.message}`);
        reject(error);
      };

      readStream.on('error', handleError);
      writeStream.on('error', handleError);

      // 开始传输
      readStream.pipe(writeStream);
    });
  }

  /**
   * 批量上传文件
   * @param {Array|string} patterns - 文件模式数组或单个模式
   * @param {string} remoteDir - 远程目录
   * @param {Object} options - 选项
   * @returns {Promise<Object>} - 上传结果
   */
  async uploadFiles(patterns, remoteDir, options = {}) {
    if (!this.isConnected()) {
      throw new Error('未连接到 SFTP 服务器');
    }
    
    if (!this.batchTransfer) {
      throw new Error('批量传输功能未初始化');
    }
    
    return await this.batchTransfer.uploadFiles(patterns, remoteDir, options);
  }

  /**
   * 批量下载文件
   * @param {Array|string} patterns - 远程文件模式数组或单个模式
   * @param {string} localDir - 本地目录
   * @param {Object} options - 选项
   * @returns {Promise<Object>} - 下载结果
   */
  async downloadFiles(patterns, localDir, options = {}) {
    if (!this.isConnected()) {
      throw new Error('未连接到 SFTP 服务器');
    }
    
    if (!this.batchTransfer) {
      throw new Error('批量传输功能未初始化');
    }
    
    return await this.batchTransfer.downloadFiles(patterns, localDir, options);
  }

  async getFileInfo(remotePath) {
    if (!this.isConnected()) {
      throw new Error('未连接到 SFTP 服务器');
    }

    return new Promise((resolve, reject) => {
      this.sftp.stat(remotePath, (err, stats) => {
        if (err) {
          reject(new Error(`获取文件信息失败: ${err.message}`));
        } else {
          resolve(stats);
        }
      });
    });
  }

  /**
   * 计算本地文件的哈希值
   * @param {string} filePath - 文件路径
   * @param {string} algorithm - 哈希算法 (md5, sha1, sha256)
   * @returns {Promise<string>} 文件哈希值
   */
  async calculateLocalFileHash(filePath, algorithm = 'md5') {
    return new Promise((resolve, reject) => {
      const hash = crypto.createHash(algorithm);
      const stream = fs.createReadStream(filePath);
      
      stream.on('data', (data) => {
        hash.update(data);
      });
      
      stream.on('end', () => {
        resolve(hash.digest('hex'));
      });
      
      stream.on('error', (err) => {
        reject(new Error(`计算文件哈希失败: ${err.message}`));
      });
    });
  }

  /**
   * 计算远程文件的哈希值
   * @param {string} remotePath - 远程文件路径
   * @param {string} algorithm - 哈希算法 (md5, sha1, sha256)
   * @returns {Promise<string>} 远程文件哈希值
   */
  async calculateRemoteFileHash(remotePath, algorithm = 'md5') {
    return new Promise((resolve, reject) => {
      const hash = crypto.createHash(algorithm);
      const stream = this.sftp.createReadStream(remotePath);
      
      stream.on('data', (data) => {
        hash.update(data);
      });
      
      stream.on('end', () => {
        resolve(hash.digest('hex'));
      });
      
      stream.on('error', (err) => {
        reject(new Error(`计算远程文件哈希失败: ${err.message}`));
      });
    });
  }

  /**
   * 验证文件完整性
   * @param {string} localPath - 本地文件路径
   * @param {string} remotePath - 远程文件路径
   * @param {string} algorithm - 哈希算法
   * @returns {Promise<boolean>} - 是否匹配
   */
  async verifyFileIntegrity(localPath, remotePath, algorithm = 'md5') {
    try {
      const localHash = await this.calculateLocalFileHash(localPath, algorithm);
      const remoteHash = await this.calculateRemoteFileHash(remotePath, algorithm);
      return localHash === remoteHash;
    } catch (error) {
      Logger.error(`完整性验证失败: ${error.message}`);
      return false;
    }
  }


  /**
   * 删除远程文件
   * @param {string} remotePath - 远程文件路径
   * @returns {Promise<void>}
   */
  async deleteFile(remotePath) {
    if (!this.isConnected()) {
      throw new Error('未连接到 SFTP 服务器');
    }

    return new Promise((resolve, reject) => {
      this.sftp.unlink(remotePath, (err) => {
        if (err) {
          reject(new Error(`删除文件失败: ${err.message}`));
        } else {
          Logger.success(`文件已删除: ${remotePath}`);
          resolve();
        }
      });
    });
  }
}

